﻿using System;
using EPiServer.Personalization.VisitorGroups;
using EPiServer.Personalization.VisitorGroups.Criteria;
using System.ComponentModel.DataAnnotations;
using EPiServer.Data.Dynamic;
using System.Web;
using EPiServer.Data;

namespace CriteriaPack.EventTimeCriterion
{
    public class EventCriterionModel : CriterionModelBase
    {
        private DateTime _startTime;
        private DateTime _endTime;
        private RepeatType _repeatType;

        /// <summary>
        /// Gets or sets the database identifier of this model.
        /// </summary>
        public EPiServer.Data.Identity Id { get; set; }

        /// <summary>
        /// Gets or sets the start time.
        /// </summary>
        /// <value>The start time.</value>
        [Required]
        [DojoWidget(WidgetType = "dijit.form.DateTextBox", LabelTranslationKey = "/shell/cms/visitorgroups/criteria/event/starttime")]
        public DateTime StartTime
        {
            get { return _startTime; }
            set { _startTime = value; } 
        }

        /// <summary>
        /// Gets or sets the end time.
        /// </summary>
        /// <value>The end time.</value>
        [Required]
        [DojoWidget(WidgetType = "dijit.form.DateTextBox", LabelTranslationKey = "/shell/cms/visitorgroups/criteria/event/endtime")]
        public DateTime EndTime
        {
            get { return _endTime; }
            set { _endTime = value; } 
        }

        /// <summary>
        /// Gets or sets the repeat type.
        /// </summary>
        /// <value>The repeat type.</value>
        [DojoWidget(SelectionFactoryType = typeof(EPiServer.Web.Mvc.VisitorGroups.EnumSelectionFactory), AdditionalOptions = "{ selectOnClick: true }")]
        public RepeatType RepeatType
        {
            get
            {
                return this._repeatType;
            }
            set
            {
                this._repeatType = value;
            }
        }


        public override ICriterionModel Copy()
        {
            return base.ShallowCopy();
        }
    }
    [VisitorGroupCriterion(
        Category = "Time and Place Criteria",
        Description = "Match specific period time",
        DisplayName = "Event")]     
    public class EventCriterion : CriterionBase<EventCriterionModel>
    {
        private ICurrentTimeProvider _currentTimeProvider;

        /// <summary>
        /// Initializes a new instance
        /// </summary>
        public EventCriterion()
        {
            _currentTimeProvider = new ServerCurrentTimeProvider();
        }
        
        public override bool IsMatch(System.Security.Principal.IPrincipal principal, HttpContextBase httpContext)
        {
            DateTime from = this.Model.StartTime;
            DateTime to = this.Model.EndTime;
            DateTime now = _currentTimeProvider.GetNow(httpContext.Request);
            RepeatType repeat = this.Model.RepeatType; //never, every month, every year            

            bool match = false;
             
            switch (repeat)
            {
                case RepeatType.EveryMonth:
                    now = GetValidDate(from.Year, from.Month, now.Day);
                    break;
                case RepeatType.EveryYear:
                    now = GetValidDate(from.Year, now.Month, now.Day);                    
                    break;        
            }

            if (from.Equals(to))
                match = (now >= from) && GetValidDate(now.Year, now.Month, now.Day) <= to;
            else
                match = (now >= from) && (now <= to);

            return match;             
        }

        /// <summary>
        /// Get the closest valid date
        /// </summary>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <param name="day"></param>
        /// <returns></returns>
        public DateTime GetValidDate(int year, int month, int day)
        {             
            int dayMax = DateTime.DaysInMonth(year, month);

            if (day > dayMax || day < 1)
                day = dayMax;

            return new DateTime(year, month, day); 
        }

        private class ServerCurrentTimeProvider : ICurrentTimeProvider
        {
            #region ITimeProvider Members

            public DateTime GetNow(HttpRequestBase request)
            {
                return DateTime.Now;
            }

            #endregion
        }
    }

    /// <summary>
    /// Repeat type for event criterion
    /// </summary>
    public enum RepeatType
    {
        Never,
        EveryMonth,
        EveryYear
    }
}
